﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Word = NetOffice.WordApi;
using NetOffice.WordApi.Enums;

// note: 用語
//   RefList=相互参照の項目(番号+タイトル名)を列挙したリスト
//   RefTab=RefListを表示するタブ
//   LabelList=ラベル名(見出し、図、表...)を列挙したリスト

namespace WordCrossRefAddin {

    public partial class CrossRefPane : UserControl {

        public readonly Word.Application WordApp;
        public readonly Word.Window WordWindow;
        RefListProp[] _RefListProps; // 順序はラベル名リストと同じ

        public CrossRefPane() {

            InitializeComponent();

            if (this.DesignMode)
                return;

            this.WordApp = Addin.Core.WordApp;
            this.WordWindow = Addin.Core.WordApp.ActiveWindow;
        }

        // sec: ラベル名リストに係る機能

        public void RefreshLabelList(bool initialize = false) {
            // note: ラベル名のリストを更新

            if (!initialize) { // if: リストの更新の場合(初期化ではない)
                this.SaveConfig_LabelList();
            }

            _UICrossLabelList.SuspendLayout(); // ちらつき防止

            // sec: 内部データを生成

            var props = new List<RefListProp>();
            props.Add(new RefListProp() {
                Name = "見出し",
                RefType = WdReferenceType.wdRefTypeHeading,
                RefKind = WdReferenceKind.wdNumberNoContext
            });
            props.Add(new RefListProp() {
                Name = "番号付項目",
                RefType = WdReferenceType.wdRefTypeNumberedItem,
                RefKind = WdReferenceKind.wdNumberNoContext
            });
            props.Add(new RefListProp() {
                Name = "脚注",
                RefType = WdReferenceType.wdRefTypeFootnote,
                RefKind = WdReferenceKind.wdNumberNoContext
            });
            props.Add(new RefListProp() {
                Name = "文末脚注",
                RefType = WdReferenceType.wdRefTypeEndnote,
                RefKind = WdReferenceKind.wdNumberNoContext
            });
            props.Add(new RefListProp() {
                Name = "ブックマーク",
                RefType = WdReferenceType.wdRefTypeBookmark,
                RefKind = WdReferenceKind.wdNumberNoContext
            });

            var app = this.WordApp;
            foreach (var label in app.CaptionLabels) {

                props.Add(new RefListProp() {
                    Name = label.Name,
                    RefType = label.Name,
                    RefKind = WdReferenceKind.wdOnlyLabelAndNumber
                });
            }

            // sec: GUIに反映

            _UICrossLabelList.Items.Clear();
            foreach (var item in props) {
                _UICrossLabelList.Items.Add(item.Name);
            }

            _RefListProps = props.ToArray();

            // sec: チェック項目を復元

            this.LoadConfig_LabelList();

            _UICrossLabelList.ResumeLayout(false); // 処理の末尾に配置
        }
        
        public void LoadConfig_LabelList() {

            // sec: ラベル名の選択状態を復元

            var names_ckd = Addin.Core.Config.RefPane.CheckedLabels;

            foreach (ListViewItem item in _UICrossLabelList.Items) {

                var is_found = names_ckd.Any(name => name == item.Text); // 前回チェックされていたラベル名がある
                if (item.Checked != is_found) {
                    item.Checked = is_found;
                }
            }
        }

        public void SaveConfig_LabelList() {

            // sec: ラベル名の選択状態を抽出

            var names_ckd = _UICrossLabelList.CheckedItems
                .Cast<ListViewItem>()
                .Select(item => item.Text)
                .ToArray();

            // sec: 設定へ保存

            Addin.Core.Config.RefPane.CheckedLabels = names_ckd;
        }

        // sec: 相互参照タブに係る機能

        public void SyncroLabelListAndRefTabs(bool initialize = false) {
            // note: ラベル名リストのチェック項目と表示タブ項目を同期

            if (!initialize) { // if: リストの更新の場合(初期化ではない)
                this.SaveConfig_RefTab();
            }

            _UITabControl.SelectedIndex = -1; // ちらつき防止?
            _UITabControl.SuspendLayout(); // ちらつき防止

            // sec: ラベル名を抽出

            var sets_ckd = _UICrossLabelList.CheckedItems
                .Cast<ListViewItem>()
                .Select(item => new { Label = item.Text, Index = item.Index })
                .ToArray();

            var tabs = _UITabControl.TabPages;
            var n_tabs = tabs.Count;
            var tab_config = tabs[n_tabs - 1]; // 設定タブを取得
            var sets_tab = tabs
                .Cast<TabPage>()
                .Take(n_tabs - 1) // 設定タブを省く
                .Select(item => new { Label = item.Text, Tab = item })
                .ToArray();

            // sec: タブをクリア

            tabs.Clear();

            // sec: タブをラベル名リスト順に追加

            foreach (var set_ckd in sets_ckd) {

                // sec: 同じラベル名を探す

                var is_already = false;
                TabPage tab_found = null;
                foreach (var set_tab in sets_tab) {

                    if (set_tab.Label == set_ckd.Label) { // if: 既にタブは表示中
                        is_already = true;
                        tab_found = set_tab.Tab;
                        break;
                    }
                }

                // sec: タブを追加

                if (is_already) { // if: 既にタブは表示中
                    tabs.Add(tab_found);

                } else { // if: タブがない
                    var tab_new = this.CreateRefTab(_RefListProps[set_ckd.Index]);
                    tabs.Add(tab_new);
                }
            }

            // sec: タブをリリース

            foreach (var set_tab in sets_tab) {

                var is_found = sets_ckd.Any(set_ckd => set_ckd.Label == set_tab.Label);
                if (!is_found) {
                    set_tab.Tab.Dispose();
                }
            }

            // sec: 設定タブを末尾に追加

            tabs.Add(tab_config);

            this.LoadConfig_RefTab();

            _UITabControl.ResumeLayout(false); // 処理の末尾に配置
        }

        public TabPage CreateRefTab(RefListProp prop) {

            var tab = new TabPage(prop.Name) {
                Padding = new Padding(3),
                UseVisualStyleBackColor = true
            };
            tab.Controls.Add(new CrossRefList(prop) {
                Dock = DockStyle.Fill
            });

            return tab;
        }

        public void LoadConfig_RefTab() {

            // sec: 選択タブを復元

            var n_tabs = _UITabControl.TabPages.Count;
            var label_sel = Addin.Core.Config.RefPane.SelectedLabelInTabs;
            var is_selected = false;
            for (var i_tab = 0; i_tab < n_tabs; i_tab++) {

                var tab = _UITabControl.TabPages[i_tab];

                if (tab.Text == label_sel) {
                    _UITabControl.SelectedIndex = i_tab;
                    is_selected = true;
                    break;
                }
            }
            if (!is_selected) { // if: 選択タブを復元できない場合
                _UITabControl.SelectedIndex = n_tabs - 1; // 設定タブを選択
            }
        }

        public void SaveConfig_RefTab() {

            // sec: 選択タブを記録

            Addin.Core.Config.RefPane.SelectedLabelInTabs = _UITabControl.SelectedTab.Text;
        }

        // sec: GUI events

        bool _IsEnable_ItemChecked = true;

        private void CrossRefPane_Load(object sender, EventArgs e) {

            _IsEnable_ItemChecked = false;
            this.RefreshLabelList(initialize: true);
            _IsEnable_ItemChecked = true;

            this.SyncroLabelListAndRefTabs(initialize: true);
        }

        public new void Dispose() {

            this.SaveConfig_LabelList();
            this.SaveConfig_RefTab();

            base.Dispose();
        }

        private void _UIUpdateCrossRefList_Click(object sender, EventArgs e) {

            _IsEnable_ItemChecked = false;
            this.RefreshLabelList();
            _IsEnable_ItemChecked = true;

            this.SyncroLabelListAndRefTabs();
        }

        private void _UICrossLabelList_ItemChecked(object sender, ItemCheckedEventArgs e) {

            if (_IsEnable_ItemChecked)
                this.SyncroLabelListAndRefTabs();
        }
    }

    public class RefListProp {

        public string Name;
        public object RefType;
        public WdReferenceKind RefKind;
    }
}